package com.markhsiu.common.memory;

/**
 *  
 *  内存池字节流buffer
 * 
 */
 final class PoolByteBuff extends ByteBuff{

	private static final int LENGTH = MMBlock.LENGTH_MAX; 
	private int capacity;//容量
	private int writerIndex;//写索引
	
	private UnsafeMemory buffer;
	private MMBlock[] blocks;
	private int blockIndex;//blocks索引 0...n
	private int blockPosition;//block位置  0..n
	
	public PoolByteBuff() {}

	public PoolByteBuff(UnsafeMemory buffer,MMBlock[] blocks,int capacity) {
		this.buffer = buffer;
		this.blocks = blocks;
		this.capacity = capacity;
		this.writerIndex = 0;
	}

	public PoolByteBuff putInt(int value) {
		this.ensureWritable(4);
		int space = LENGTH - blockPosition;
		int offset = blocks[blockIndex].offset();
		if(space > 4){	
			buffer.putInt(offset + blockPosition, value);
			blockPosition += 4;
		} else if(space == 4){
			buffer.putInt(offset + blockPosition, value);
			blockIndex ++;
			blockPosition = 0;
		} else {
			int[] bi = new int[4];
			for (int i = 0; i < space; i++) {
				bi[i] = offset + blockPosition++;
			}
			blockPosition = 0;
			blockIndex ++;
			offset = blocks[blockIndex].offset();
			for (int i = 0; i < 4 - space; i++) {
				bi[space++] = offset + blockPosition++;
			}
			Bits.putInt(this, bi[0], bi[1], bi[2], bi[3], value);
		}
		writerIndex += 4;
		return this;
	}
	
	public final PoolByteBuff put(byte value) {
		this.ensureWritable(1);
		int space = LENGTH - blockPosition;
		int offset = blocks[blockIndex].offset();
		if(space == 1){
			buffer.putByte(offset + blockPosition, value);
			blockIndex ++;
			blockPosition = 0;
		} else {// > 1
			buffer.putByte(offset + blockPosition, value);
			blockPosition += 1;
		}
		writerIndex += 1;
		return this;
	}

	public final PoolByteBuff put(byte[] src) {
		int length = src.length;
		this.ensureWritable(length);
		int space = LENGTH - blockPosition;
		int offset = blocks[blockIndex].offset();
		if(space > length){	
			buffer.put(offset + blockPosition, src);
			blockPosition += length;
		} else if(space == length){
			buffer.put(offset + blockPosition, src);
			blockIndex ++;
			blockPosition = 0;
		} else {
			int position = 0;
			byte[] bytes = new byte[space];
			for (int i = 0; i < space; i++) {
				bytes[i] = src[position++];
			}
	
			buffer.put(offset + blockPosition, bytes);
			blockPosition = 0;
			blockIndex ++;
			
			int newLength = length - space;
			int remainder = newLength % LENGTH;
			int multiple = newLength / LENGTH;
			bytes = new byte[LENGTH];
			for (int i = 0; i < multiple; i++) {
				for (int j = 0; j < LENGTH; j++) {
					bytes[j] = src[position++];
				}
				offset = blocks[blockIndex++].offset();
				buffer.put(offset, bytes);
			}
			
			if(remainder > 0){
				bytes = new byte[remainder];
				for (int i = 0; i < remainder; i++) {
					bytes[i] = src[position++];
				}
				offset = blocks[blockIndex].offset();
				buffer.put(offset, bytes);
				blockPosition += remainder;
			}
		}
		
		writerIndex += length;
		
		return this;
	}
	
	public final UnsafeMemory buffer() {
		return buffer;
	}
	
	public final PoolByteBuff put(byte[] src, int offset, int length){
		this.ensureWritable(length);
		return this;
	}
	
	public final byte[] data() {
		byte[] data = new byte[length()];		 
		int position = 0;
		for (int i = 0; i < blockIndex; i++) {
			int offset = blocks[i].offset();
			for (int j = 0; j < LENGTH; j++) {
				data[position++] = buffer.getByte(offset+j);
			}	
		}
		int offset = blocks[blockIndex].offset();
		for (int i = 0; i < blockPosition; i++) {
			data[position++] = buffer.getByte(offset+i);
		}
		return data;
	}

	public void clear() {
		throw new IllegalArgumentException("不能调用PoolByteBuff的clear方法释放内存");
	}
	
	 void free() {
		for (MMBlock block : blocks) {
			block.free();
		}
		capacity = 0;
		writerIndex = 0;
		blocks = null;
		buffer = null;
	}
	
	public int length() {
		return writerIndex;
	}
	
	public int capacity() {
		return capacity;
	}
	
	public int writerIndex(){
		return writerIndex;
	}

	public int capacity(int newCapacity) {
		throw new IllegalArgumentException();
	}

	public int writableBytes() {
		return capacity() - writerIndex();
	}
	

	public void ensureWritable(int minWritableBytes) {		 
		if (minWritableBytes > writableBytes()) {
			throw new IllegalArgumentException("可用内存不够分配");
		}
	}

	@Override
	void _put(int index, byte b) {
		 buffer.putByte(index, b);
	}

	@Override
	byte _get(int index) {
		return buffer.getByte(index);
	}
 

	@Override
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("{capacity:");
		sb.append(capacity);
		sb.append("},{writerIndex:");
		sb.append(writerIndex);
		sb.append("},{blockIndex:");
		sb.append(blockIndex);
		sb.append("},{blockPosition:");
		sb.append(blockPosition);
		sb.append("}");
		return sb.toString();	
	}
}
